﻿//////////////////////////////////////////////////////////////////////
// <copyright file=MainWindow.cs">
//     Copyright (c) 2010
//     Released under  GNU GENERAL PUBLIC LICENSE
//     http://dev.perl.org/licenses/gpl1.html
// </copyright>
// <date> 3/3/2010 12:34:31 AM </date>
// <author> B. Endrovski </author>
// <web> http://furiouspixels.blogspot.com/ </web>
//////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;

namespace Curves
{
	public partial class MainWindow : Form
	{
		// Set current mode
		private enum AppMode { None, CVAdd, CVEdit };
		private AppMode mode = AppMode.None;

		private Curve selectedCurve;
		private int selectedCV;
		private Drawing drawing;

		public MainWindow()
		{
			InitializeComponent();
			drawing = new Drawing();

			curvesList.DataSource = drawing.Curves;
			curvesList.DisplayMember = "Name";
			curvesList.ValueMember = "Id";

			this.SetStyle(
			ControlStyles.UserPaint |
			ControlStyles.AllPaintingInWmPaint |
			ControlStyles.OptimizedDoubleBuffer, true);


			SetUpDisplay();
		}

		private void SetUpDisplay()
		{
			curveToolStrip.Enabled = false;
			deleteStripButton.Enabled = false;
			deleteToolStripMenuItem.Enabled = false;
			convertToCardinalToolStripMenuItem.Enabled = false;
			//
			if (selectedCurve != null)
			{
				properties.SelectedObject = selectedCurve;
				if (selectedCurve is CardinalCurve)
				{
					curveToolStrip.Enabled = true;
				}
				convertToCardinalToolStripMenuItem.Enabled = true;
				deleteStripButton.Enabled = true;
				deleteToolStripMenuItem.Enabled = true;
			}

			((CurrencyManager)curvesList.BindingContext[curvesList.DataSource]).Refresh();
			this.Invalidate(true);
		}

		private void toolStripContainer1_ContentPanel_MouseClick(object sender, MouseEventArgs e)
		{
			if (mode == AppMode.CVAdd && (selectedCurve is CardinalCurve))
			{
				CardinalCurve spline = (CardinalCurve)selectedCurve;
				PointF posF = new PointF(e.X, e.Y);
				spline.CV.Add(posF);
				spline.Rebuild();
				//
				this.Invalidate(true);
			}
			else if (mode == AppMode.CVEdit)
			{
				// Nothuing for now
			}
		}

		private void addCVBtn_Click(object sender, EventArgs e)
		{
			if (addCVBtn.Checked)
			{
				mode = AppMode.CVAdd;
				editCVBtn.Checked = false;
			}
			else
			{
				mode = AppMode.None;
			}
		}

		private void editCVBtn_Click(object sender, EventArgs e)
		{
			if (editCVBtn.Checked)
			{
				mode = AppMode.CVEdit;
				addCVBtn.Checked = false;
			}
			else
			{
				mode = AppMode.None;
			}
		}

		private void CV_MouseMove(object sender, MouseEventArgs e)
		{
			if (mode == AppMode.CVEdit && e.Button == MouseButtons.Left &&
				(selectedCurve is CardinalCurve) && selectedCV >= 0)
			{
				CardinalCurve curve = (CardinalCurve)selectedCurve;
				curve.MoveCV(selectedCV, new PointF(e.X, e.Y));
				this.Invalidate(true);
			}
		}

		private void drawPanel_MouseDown(object sender, MouseEventArgs e)
		{
			if (mode == AppMode.CVEdit && e.Button == MouseButtons.Left && selectedCurve.GetType() == typeof(CardinalCurve))
			{
				CardinalCurve curve = (CardinalCurve)selectedCurve;
				selectedCV = curve.GetCV(e.Location, 3.0f);
			}
		}

		private void drawPanel_MouseUp(object sender, MouseEventArgs e)
		{
			selectedCV = -1;
		}

		private void container_ContentPanel_Paint(object sender, PaintEventArgs e)
		{
			// Draw origin if needed
			if (selectedCurve != null && (selectedCurve is ScarabaeusCurve))
			{
				ScarabaeusCurve sc = (selectedCurve as ScarabaeusCurve);
				Pen pen = new Pen(new SolidBrush(Color.LightGray));
				e.Graphics.DrawLine(pen, 0, sc.Origin.Y, splitContainer.Panel1.Width, sc.Origin.Y);
				e.Graphics.DrawLine(pen, sc.Origin.X, 0, sc.Origin.X, splitContainer.Panel1.Height);
			}

			// Draw curve
			foreach (Curve c in drawing.Curves)
			{
				PointF[] ccurve = c.GetCurve();
				if (ccurve.Length >= 2)
				{
					e.Graphics.DrawLines(new Pen(new SolidBrush(c.Color), c.Thickness), ccurve);
				}
			}

			// Draw CVs if needed
			if (selectedCurve != null && (selectedCurve is CardinalCurve))
			{
				PointF[] curvecv = ((CardinalCurve)selectedCurve).CV.ToArray();
				if (curvecv.Length >= 1)
				{
					foreach (PointF pf in curvecv)
					{
						e.Graphics.FillEllipse(new SolidBrush(Color.Purple), pf.X - 2.5f, pf.Y - 2.5f, 5, 5);
					}
				}
			}			
		}

		private void properties_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
		{
			SetUpDisplay();
		}

		private void cardinalSplineToolStripMenuItem_Click(object sender, EventArgs e)
		{
			CardinalCurve curve = new CardinalCurve();
			drawing.Curves.Add(curve);
			properties.SelectedObject = curve;
			selectedCurve = curve;

			SetUpDisplay();
		}

		private void circleToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Circle circle = new Circle();
			drawing.Curves.Add(circle);
			properties.SelectedObject = circle;
			selectedCurve = circle;

			SetUpDisplay();
		}

		private void scarabaeusCurveToolStripMenuItem_Click(object sender, EventArgs e)
		{
			ScarabaeusCurve curve = new ScarabaeusCurve();
			drawing.Curves.Add(curve);
			properties.SelectedObject = curve;
			selectedCurve = curve;

			SetUpDisplay();
		}


		private void saveToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (saveFileDialog.ShowDialog() == DialogResult.OK)
			{
				// Serialization
				String filename = saveFileDialog.FileName;
				XmlSerializer s = new XmlSerializer(typeof(Drawing));
				TextWriter w = new StreamWriter(filename);
				s.Serialize(w, drawing);
				w.Close();
			}
		}

		private void openToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (openFileDialog.ShowDialog() == DialogResult.OK)
			{
				// Deserialization
				String filename = openFileDialog.FileName;
				XmlSerializer s = new XmlSerializer(typeof(Drawing));
				TextReader r = new StreamReader(filename);
				drawing = (Drawing)s.Deserialize(r);
				r.Close();
				//
				foreach (Curve c in drawing.Curves)
				{
					if (c is CardinalCurve)
						(c as CardinalCurve).Rebuild();
				}
				//
				curvesList.DataSource = drawing.Curves;
				curvesList.DisplayMember = "Name";
				curvesList.ValueMember = "Id";
				//
				SetUpDisplay();
			}			
		}

		private void newToolStripMenuItem_Click(object sender, EventArgs e)
		{
			drawing = new Drawing();
			selectedCurve = null;
			selectedCV = -1;
			SetUpDisplay();
		}

		private void curvesList_SelectedIndexChanged(object sender, EventArgs e)
		{
			int idx = curvesList.SelectedIndex;
			selectedCurve = drawing.Curves[idx];
			SetUpDisplay();
		}

		private void convertToCardinalToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (selectedCurve == null)
				return;

			ToCardinalForm convDialog = new ToCardinalForm();
			//
			if (convDialog.ShowDialog() == DialogResult.OK)
			{
				int saveSamples = selectedCurve.Samples;			// Save current tesselation
				selectedCurve.Samples = convDialog.Samples;			// Set new tessletation
				PointF[] samplePoints = selectedCurve.GetCurve();	// Sample
				selectedCurve.Samples = saveSamples;				// Restore saved tessletation
				//				
				if (samplePoints.Length >= 4)			
				{
					CardinalCurve spline = new CardinalCurve();		// Recontruct curve
					foreach (PointF p in samplePoints)
					{
						spline.CV.Add(p);
					}
					//
					if (selectedCurve is CardinalCurve)
					{
						// Rebuliding a Cardinal Curve
						spline.CurveType = (selectedCurve as CardinalCurve).CurveType;
					}
					else
					{
						// Rebuliding as Closed Curve
						spline.CV.Remove(spline.CV.Last());
						spline.CurveType = SplineType.Closed;
					}
					spline.Rebuild();
					
					// Update UI
					drawing.Curves.Add(spline);
					selectedCurve = spline;
					SetUpDisplay();
				}
			}			
		}

		private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (selectedCurve != null)
			{
				drawing.Curves.Remove(selectedCurve);
				selectedCurve = null;
				selectedCV = -1;
				SetUpDisplay();
			}
		}

		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Application.Exit();
		}

		private void helpToolStripMenuItem_Click(object sender, EventArgs e)
		{
			// A single help file for both the release and the debug version of the exe
			DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(Application.ExecutablePath));			
			di = di.Parent.Parent.Parent;
			//
			try
			{								
				System.Diagnostics.Process.Start(di.FullName + "\\Scarabaeus Curve.pdf");
			}
			catch (Exception)
			{
				MessageBox.Show("No help file found at" + di.FullName + "\\Scarabaeus Curve.pdf", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}
	}
}
